package crmdna.user;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.client.Client;
import crmdna.common.api.APIException;
import crmdna.common.api.APIResponse.Status;
import crmdna.group.Group;
import crmdna.group.Group.GroupProp;
import crmdna.user.User.Action;
import crmdna.user.User.ResourceType;
import crmdna.user.UserCore.UserProp;

public class UserTest {

  private final LocalServiceTestHelper datastoreHelper = new LocalServiceTestHelper(
      new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());
  // local implementation / test harness implementation becomes HRD
  // only if setApplyAllHighRepJobPolicy is set. If the implementation is not
  // HRD then
  // cross group transactions would fail (as master slave does not support it)

  String client = "isha";
  GroupProp sgp;

  @Before
  public void setUp() {
    datastoreHelper.setUp();
    ObjectifyFilter.complete();

    // Client.create(client);
    // sgp = Group.create(client, "Singapore", User.SUPER_USER);
    // assertEquals(1, sgp.groupId);
  }

  @After
  public void tearDown() {
    ObjectifyFilter.complete();
    datastoreHelper.tearDown();
  }

  @Test
  public void createTest() {

    // client cannot be invalid
    try {
      User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create(client);

    assertEquals(0, User.getAll("isha", User.SUPER_USER).size());

    try {
      User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals("group id should be valid", Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id 1

    // email should be valid
    try {
      User.create("isha", "sathya.tishafoundation.org", 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_INCORRECT, ex.statusCode);
    }

    // cannot add null or empty string as email
    try {
      User.create("isha", null, 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_INCORRECT, ex.statusCode);
    }

    try {
      User.create("isha", "", 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_INCORRECT, ex.statusCode);
    }

    User.create("isha", "sAThya.t@ishafoundation.org", 1, User.SUPER_USER);
    UserProp prop = User.get("isha", "sathya.t@ishafoundation.org").toProp();
    assertEquals("sathya.t@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(1, prop.userId);
    assertEquals(1, prop.groupId);

    // cannot create the same user again
    try {
      User.create("isha", "sAThya.t@ishafoundation.org", 1, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, ex.statusCode);
    }

    // next user should get id 2
    User.create("isha", "sAThya.isha@gmail.com", 1, User.SUPER_USER);
    prop = User.get("isha", "sathya.isha@gmail.com").toProp();
    assertEquals("sathya.isha@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(2, prop.userId);

    // test privilege
    String login = "login@login.com";
    User.create("isha", login, 1, User.SUPER_USER);
    try {
      User.create("isha", "sowmya@gmail.com", 1, login);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    User.addOrDeletePrivilege("isha", login, ResourceType.USER, 0, Action.WRITE, true,
        User.SUPER_USER);

    User.create("isha", "sowmya@gmail.com", 1, login); // no exception
    prop = User.get("isha", "sowmya@gmail.com").toProp();
    assertEquals("sowmya@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(4, prop.userId); // login@login.com would be 3
  }

  @Test
  public void getTest() {

    // client cannot be invalid
    try {
      User.get("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // null if not existing
    assertEquals(null, User.get("isha", "sathya.t@ishafoundation.org"));

    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id: 1

    User.create("isha", "sAThya.t@ishafoundation.org", 1, User.SUPER_USER);
    UserProp prop = User.get("isha", "sathya.t@ishafoundation.org").toProp();
    assertEquals("sathya.t@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(1, prop.userId);
    assertEquals(1, prop.groupId);

    // add some privileges
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.WRITE, true, User.SUPER_USER);
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, true, User.SUPER_USER);
    prop = User.get("isha", "sathya.t@ishafoundation.org").toProp();
    assertEquals("sathya.t@ishafoundation.org", prop.email);
    assertEquals(2, prop.privileges.size());
    assertEquals(UserCore.getPrivilege(ResourceType.GROUP.toString(), 1, Action.READ.toString()),
        prop.privileges.first());
    assertEquals(UserCore.getPrivilege(ResourceType.GROUP.toString(), 1, Action.WRITE.toString()),
        prop.privileges.last());
    assertEquals(1, prop.userId);
    assertEquals(1, prop.groupId);
  }

  @Test
  public void safeGetTest() {
    String user = "sathya.t@ishafoundation.org";
    String client = "isha";

    // client cannot be invalid
    try {
      User.safeGet(client, user);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals("client should be valid", Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create(client);

    try {
      User.safeGet(client, user);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals("user email should exist", Status.ERROR_INVALID_USER, ex.statusCode);
    }

    long groupId = Group.create(client, "sgp", User.SUPER_USER).groupId;
    UserCore.create(client, user, groupId);

    assertEquals("can get by email", user, User.safeGet(client, user).toProp().email);
  }

  @Test
  public void getAllTest() {

    // client cannot be invalid
    try {
      User.get("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // 0 when there are no users
    assertEquals(0, User.getAll("isha", User.SUPER_USER).size());

    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id 1
    Group.create("isha", "Malaysia/KL", User.SUPER_USER); // will be
                                                          // allocated id 2

    User.create("isha", "weibeng@gmail.com", 2, User.SUPER_USER);
    User.create("isha", "sAThya.t@ishafoundation.org", 1, User.SUPER_USER);
    User.create("isha", "Thulasidhar@gmail.com", 1, User.SUPER_USER);
    User.create("isha", "TIna@ishafoundation.org", 1, User.SUPER_USER);

    List<UserProp> props = User.getAll("isha", User.SUPER_USER);
    assertEquals(4, props.size());

    // should be sorted by email. ids should be allocated in same order as
    // create
    UserProp prop = props.get(0);
    assertEquals("sathya.t@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(2, prop.userId);
    assertEquals(1, prop.groupId);

    prop = props.get(1);
    assertEquals("thulasidhar@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(3, prop.userId);
    assertEquals(1, prop.groupId);

    prop = props.get(2);
    assertEquals("tina@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(4, prop.userId);
    assertEquals(1, prop.groupId);

    prop = props.get(3);
    assertEquals("weibeng@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(1, prop.userId);
    assertEquals(2, prop.groupId);
  }

  @Test
  public void getAllForCenterTest() {

    // client cannot be invalid
    try {
      User.get("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // 0 when there are no users
    assertEquals(0, User.getAll("isha", User.SUPER_USER).size());

    GroupProp sgp = Group.create("isha", "Singapore", User.SUPER_USER); // will
                                                                        // be
                                                                        // allocated
                                                                        // id
                                                                        // 1
    GroupProp kl = Group.create("isha", "Malaysia/KL", User.SUPER_USER); // will
                                                                         // be
                                                                         // allocated
                                                                         // id
                                                                         // 2

    User.create("isha", "weibeng@gmail.com", 2, User.SUPER_USER);
    User.create("isha", "sAThya.t@ishafoundation.org", 1, User.SUPER_USER);
    User.create("isha", "Thulasidhar@gmail.com", 1, User.SUPER_USER);
    User.create("isha", "TIna@ishafoundation.org", 1, User.SUPER_USER);

    List<UserProp> props = User.getAllForGroup("isha", sgp.groupId);
    assertEquals(3, props.size());

    // should be sorted by email. ids should be allocated in same order as
    // create
    UserProp prop = props.get(0);
    assertEquals("sathya.t@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(2, prop.userId);
    assertEquals(1, prop.groupId);

    prop = props.get(1);
    assertEquals("thulasidhar@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(3, prop.userId);
    assertEquals(1, prop.groupId);

    prop = props.get(2);
    assertEquals("tina@ishafoundation.org", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(4, prop.userId);
    assertEquals(1, prop.groupId);

    props = User.getAllForGroup("isha", kl.groupId);
    assertEquals(1, props.size());

    prop = props.get(0);
    assertEquals("weibeng@gmail.com", prop.email);
    assertEquals(0, prop.privileges.size());
    assertEquals(1, prop.userId);
    assertEquals(2, prop.groupId);
  }

  @Test
  public void updateEmailTest() {

    // client cannot be invalid
    try {
      User.get("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");
    Group.create("isha", "Singapore", User.SUPER_USER); // groupId will be 1

    User.create("isha", "sathya.t@ishaFoundation.org", 1, User.SUPER_USER);
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, true, User.SUPER_USER);
    User.create("isha", "shiva@gmail.com", 1, User.SUPER_USER);

    assertEquals(2, User.getAll("isha", User.SUPER_USER).size());

    assertEquals(1, User.get("isha", "sathya.t@ishafoundation.org").userId);

    // new email cannot be invalid
    try {
      User.updateEmail("isha", "sathya.t@ishafoundation.org", "sathya.ishagmail.com",
          User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_INCORRECT, ex.statusCode);
    }

    User.updateEmail("isha", "sathya.t@ishafoundation.org", "sathya.isha@gmail.com",
        User.SUPER_USER);

    assertTrue(null != User.get("isha", "sathya.isha@gmail.com"));
    assertEquals(1, User.get("isha", "sathya.isha@gmail.com").userId); // same
                                                                       // id
                                                                       // should
                                                                       // be
                                                                       // retained
    assertEquals(1, User.get("isha", "sathya.isha@gmail.com").groupId); // group
                                                                        // id
                                                                        // should
                                                                        // be
                                                                        // retained
    // same permissions should be retained
    assertEquals(1, User.get("isha", "sathya.isha@gmail.com").privileges.size());
    User.ensureAccess("isha", "sathya.isha@gmail.com", ResourceType.GROUP, 1, Action.READ);

    assertEquals(null, User.get("isha", "sathya.t@ishafoundation.org"));

    // cannot change to an existing id
    try {
      User.updateEmail("isha", "sathya.isha@gmail.com", "shiva@gmail.com", User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, ex.statusCode);
    }

    // can specify the same email
    User.updateEmail("isha", "sathya.isha@gmail.com", "sathya.isha@gmail.com", User.SUPER_USER);

    // test privileges
    String login = "login@login.com";
    User.create("isha", login, 1, User.SUPER_USER);
    try {
      User.updateEmail("isha", "sathya.isha@gmail.com", "shiva@gmail.com", login);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    User.addOrDeletePrivilege("isha", login, ResourceType.USER, 0, Action.WRITE, true,
        User.SUPER_USER);

    User.updateEmail("isha", "sathya.isha@gmail.com", "sowmya@gmail.com", login); // no exception
    UserProp prop = User.get("isha", "sowmya@gmail.com").toProp();
    assertEquals("sowmya@gmail.com", prop.email);
    assertEquals(1, prop.userId); // same id should be retained
  }

  @Test
  public void updateGroupTest() {

    // client cannot be invalid
    try {
      User.get("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");
    Group.create("isha", "Singapore", User.SUPER_USER); // groupId will be 1
    Group.create("isha", "Malaysia/KL", User.SUPER_USER); // groupId will be
                                                          // 2
    assertEquals(2, Group.getAll("isha").size());

    final String email = "sathya.t@ishaFoundation.org";

    User.create("isha", email, 1, User.SUPER_USER);
    User.addOrDeletePrivilege("isha", email, ResourceType.GROUP, 1, Action.READ, true,
        User.SUPER_USER);

    assertEquals(1, User.getAll("isha", User.SUPER_USER).size());

    assertEquals(1, User.get("isha", email).userId);

    // new group cannot be invalid
    try {
      User.updateGroup("isha", email, 4, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals("new group id should be valid", Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    User.updateGroup("isha", "sathya.t@ishafoundation.org", 2, User.SUPER_USER);

    UserProp prop = User.get("isha", email).toProp();
    assertTrue(null != prop);
    assertEquals(2, prop.groupId);
    // same permissions should be retained
    assertEquals(1, prop.privileges.size());
    User.ensureAccess("isha", email, ResourceType.GROUP, 1, Action.READ);

    // test privileges
    String login = "login@login.com";
    User.create("isha", login, 1, User.SUPER_USER);
    try {
      User.updateGroup("isha", email, 1, login);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    User.addOrDeletePrivilege("isha", login, ResourceType.USER, 0, Action.WRITE, true,
        User.SUPER_USER);

    User.updateGroup("isha", email, 1, login);// no exception
    prop = User.get("isha", email).toProp();
    assertEquals(email.toLowerCase(), prop.email);
    assertEquals(1, prop.groupId);
  }

  @Test
  public void ensureAccessTest() {
    // client cannot be invalid
    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // user should be valid
    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
    }

    Group.create("isha", "Singapore", User.SUPER_USER);
    // will be allocated id 1

    User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);

    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, true, User.SUPER_USER);

    User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
    // no exception

    // remove privilege
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, false, User.SUPER_USER);

    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    // always true for superuser
    User.ensureAccess("isha", User.SUPER_USER, ResourceType.USER, 0, Action.WRITE);
    User.ensureAccess("isha", User.SUPER_USER, ResourceType.USER, 0, Action.READ);
    User.ensureAccess("isha", User.SUPER_USER, ResourceType.GROUP, 0, Action.READ);
    User.ensureAccess("isha", User.SUPER_USER, ResourceType.GROUP, 0, Action.WRITE);
  }

  @Test
  public void hasAccessTest() {
    // client cannot be invalid
    try {
      User.hasAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // user should be valid
    try {
      User.hasAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
    }

    Group.create("isha", "Singapore", User.SUPER_USER);
    // will be allocated id 1

    User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);


    boolean access =
        User.hasAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
    assertEquals(false, access);


    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, true, User.SUPER_USER);

    access =
        User.hasAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
    assertEquals(true, access);

    // remove privilege
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.READ, false, User.SUPER_USER);


    access =
        User.hasAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
    assertEquals(false, access);


    // always true for superuser
    access = User.hasAccess("isha", User.SUPER_USER, ResourceType.USER, 0, Action.WRITE);
    assertEquals(true, access);
    access = User.hasAccess("isha", User.SUPER_USER, ResourceType.USER, 0, Action.READ);
    assertEquals(true, access);
    access = User.hasAccess("isha", User.SUPER_USER, ResourceType.GROUP, 0, Action.READ);
    assertEquals(true, access);
    access = User.hasAccess("isha", User.SUPER_USER, ResourceType.GROUP, 0, Action.WRITE);
    assertEquals(true, access);
  }


  @Test
  public void ensureValidUserTest() {
    // client cannot be invalid
    try {
      User.ensureValidUser("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    try {
      User.ensureValidUser("isha", "sathya.t@ishafoundation.org");
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
    }

    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id 1
    User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);
    User.ensureValidUser("isha", "sathya.t@ishafoundation.org"); // no
                                                                 // exception

    // always true for superuser
    User.ensureValidUser("isha", User.SUPER_USER);
  }

  @Test
  public void addOrDeletePrivilegeTest() {
    // client cannot be invalid
    try {
      User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
          Action.READ, true, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");

    // user cannot be invalid
    try {
      User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
          Action.WRITE, true, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
    }

    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id 1
    User.create("isha", "sathya.t@ishafoundation.org", 1, User.SUPER_USER);

    // add privilege and ensureAccess
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.WRITE, true, User.SUPER_USER);
    User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.WRITE);

    // should be able to add privilege again
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.WRITE, true, User.SUPER_USER);
    User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.WRITE);

    // remove privilege
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.WRITE, false, User.SUPER_USER);
    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    // should be able to remove again without exception
    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1,
        Action.WRITE, false, User.SUPER_USER);
    try {
      User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 1, Action.READ);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    // test privileges
    String login = "login@gmail.com";
    try {
      User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 2,
          Action.WRITE, true, login);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
    }

    User.create("isha", login, 1, User.SUPER_USER);
    try {
      User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 2,
          Action.WRITE, true, login);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    // give required permission to login
    User.addOrDeletePrivilege("isha", login, ResourceType.USER, 0, Action.WRITE, true,
        User.SUPER_USER);

    User.addOrDeletePrivilege("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 2,
        Action.WRITE, true, login); // no
                                    // exception
    User.ensureAccess("isha", "sathya.t@ishafoundation.org", ResourceType.GROUP, 2, Action.WRITE);
  }

  @Test
  public void getResourcesTest() {
    String email = "sathya.t@ishafoundation.org";

    String client = "isha";
    Client.create(client);
    GroupProp sgp = Group.create(client, "Singapore", User.SUPER_USER);
    assertEquals(1, sgp.groupId);

    User.create(client, email, 1, User.SUPER_USER);
    User.addOrDeletePrivilege(client, email, ResourceType.GROUP, 1, Action.WRITE, true,
        User.SUPER_USER);
    User.addOrDeletePrivilege(client, email, ResourceType.GROUP, 2, Action.WRITE, true,
        User.SUPER_USER);

    Set<Long> resources = User.getResources(client, email, ResourceType.GROUP, Action.WRITE);
    assertEquals(2, resources.size());
    assertTrue(resources.contains((long) 1));
    assertTrue(resources.contains((long) 2));

    resources = User.getResources(client, email, ResourceType.GROUP, Action.READ);
    assertEquals(0, resources.size());
  }

  @Test
  public void clonePrivilegesTest() {
    final String login = "login@login.com";
    final String sourceEmail = "source@gmail.com";
    final String targetEmail = "target@gmail.com";

    // client cannot be invalid
    try {
      User.clonePrivileges("isha", sourceEmail, targetEmail, login);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");
    Group.create("isha", "Singapore", User.SUPER_USER); // will be allocated
                                                        // id 1
    User.create("isha", login, 1, User.SUPER_USER);

    // should have correct privilege
    try {
      User.clonePrivileges("isha", sourceEmail, targetEmail, login);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    }

    User.addOrDeletePrivilege("isha", login, ResourceType.USER, 0, Action.WRITE, true,
        User.SUPER_USER);

    try {
      User.clonePrivileges("isha", sourceEmail, targetEmail, User.SUPER_USER);
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals("source email and target email should be valid users",
          Status.ERROR_INVALID_USER, ex.statusCode);
    }

    User.create("isha", sourceEmail, 1, User.SUPER_USER); // id: 2
    User.create("isha", targetEmail, 1, User.SUPER_USER); // id: 3
    User.addOrDeletePrivilege("isha", targetEmail, ResourceType.GROUP, 1, Action.READ, true,
        User.SUPER_USER);
    User.addOrDeletePrivilege("isha", targetEmail, ResourceType.GROUP, 2, Action.WRITE, true,
        User.SUPER_USER);

    User.clonePrivileges("isha", sourceEmail, targetEmail, login);
    crmdna.user.UserCore.UserProp prop = User.get("isha", sourceEmail).toProp();
    assertEquals(2, prop.userId);
    assertEquals(0, prop.privileges.size());
    prop = User.get("isha", targetEmail).toProp();
    assertEquals(3, prop.userId);
    assertEquals(0, prop.privileges.size());

    // add some privileges to source
    User.addOrDeletePrivilege("isha", sourceEmail, ResourceType.GROUP, 1, Action.READ, true,
        User.SUPER_USER);
    User.addOrDeletePrivilege("isha", sourceEmail, ResourceType.GROUP, 2, Action.WRITE, true,
        User.SUPER_USER);

    User.clonePrivileges("isha", sourceEmail, targetEmail, login);
    prop = User.get("isha", sourceEmail).toProp();
    assertEquals(2, prop.userId);
    assertEquals(2, prop.privileges.size());
    assertEquals(1, prop.groupId);

    prop = User.get("isha", targetEmail).toProp();
    assertEquals(3, prop.userId);
    assertEquals(2, prop.privileges.size());
    assertEquals(1, prop.groupId);
    assertTrue(prop.privileges.contains(UserCore.getPrivilege(ResourceType.GROUP.toString(), 1,
        Action.READ.toString())));
    assertTrue(prop.privileges.contains(UserCore.getPrivilege(ResourceType.GROUP.toString(), 2,
        Action.WRITE.toString())));
  }
}
